package com.sunfeng.n3;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 *
 *  保护新暂停模式   join  就是运用了保护性暂停模式
 *
 *  保护性暂停模式（Guarded Suspension Design Pattern）：当线程在访问某个对象时，发现条件不满足时，就暂时挂起等待条件满足时再次访问。
 *
 * @author sunfeng
 */
@Slf4j(topic = "c.Test20")
public class Test20{
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();

        new Thread(() -> {
            log.debug("线程【{}】,开始运行",Thread.currentThread().getName());
            Object o = guardedObject.get(4000);
            log.debug("获取到数据,{}", o);

        },"T1").start();

        new Thread(() -> {
            log.debug("线程【{}】,开始运行",Thread.currentThread().getName());
            try {
                TimeUnit.MILLISECONDS.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            guardedObject.setResponse(new Object());
        },"T2").start();
    }
}

@Slf4j(topic = "c.GuardedObject")
class GuardedObject {

    private final Object lock = new Object();
    private Object response;

    public Object get(long millis) {

        synchronized (lock){
            long start=System.currentTimeMillis();
            long passTime=0;
            while (null==response){
                // 重新计算等待时间
                long waitTime=millis-passTime;

                if(waitTime<=0){
                    break;
                }
                try {
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passTime=System.currentTimeMillis()-start;

            }
        }


        return response;
    }

    public void setResponse(Object response) {
        synchronized (lock) {
            this.response = response;
            log.debug("开始唤醒");
            lock.notifyAll();
        }
    }

}
